package config;

import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.io.ClassPathResource;

import bean.Corporation;
import bean.Person;
import context.CustomApplicationListener;

// @Configuration注解表示注解的类声明有一个或多个包含@Bean注解的方法，并可能被Spring容器处理以在运行时为这些Bean生成Bean定义和服务请求
@Configuration
// @ComponentScan表示配置组件扫描指令，它与@Configuration注解类一起使用，并提供与<context:component-scan>元素作用相同的支持
@ComponentScan(basePackages = "context")
public class SpringConfig {
    // bean的默认名称是注解的方法的名称
    @Bean
    @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON)
    public Calendar calendar() {
        return Calendar.getInstance();
    }
    
    // 获取名称为calendar的bean，作为Calendar类的变量c的引用
    @Autowired
    @Qualifier("calendar")
    private Calendar c3;
    
    @Bean
    public Date now() {
        return new Date();
    }
    
    // 指定Bean的name属性后，bean的名称即name的属性值
    @Bean(name = "dt1")
    public Date firstDate(@Autowired @Qualifier(value = "calendar") Calendar c1) {
        c1.set(90, 10, 8);
        return new Date(c1.getTimeInMillis());
    }
    
    @Bean(name = "dt2")
    @Resource(name = "calendar")
    public Date secondDate(Calendar c2) {
        c2.set(87, 6, 15);
        Date date = new Date(c2.getTimeInMillis());
        return date;
    }
    
    @Bean
    public Date dt3() {
        c3.set(92, 3, 27);
        Date date = new Date(c3.getTimeInMillis());
        return date;
    }
    
    @Bean(name = "p1")
    public Person person1(@Autowired @Qualifier(value = "dt1") Date date) {
        Person p = new Person();
        p.setName("Fidel");
        p.setMale(true);
        p.setBirthday(date);
        p.setAddress("Cuba");
        return p;
    }
    
    @Bean
    public Person p2(@Autowired @Qualifier(value = "dt2") Date date) {
        Person p = new Person();
        p.setName("Kali");
        p.setMale(false);
        p.setBirthday(date);
        p.setAddress("France");
        return p;
    }
    
    @Bean
    public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        ClassPathResource resource = new ClassPathResource("prop/person.properties");
        configurer.setLocation(resource);
        return configurer;
    }
    
    // 从属性源占位符编辑器中获取名称为name1的属性值
    @Value("${name1}")
    private String name;
    
    @Value("${name2}")
    private boolean male;
    
    @Value("${name3}")
    private String address;
    
    @Bean(name = "p3")
    public Person person3() {
        Person p = new Person();
        p.setName(name);
        p.setMale(male);
        p.setBirthday(dt3());
        p.setAddress(address);
        return p;
    }
    
    @Resource(name = "p1")
    private Person firstPerson;
    
    @Resource(name = "p2")
    private Person secondPerson;
    
    @Bean
    public Corporation corporation(@Autowired @Qualifier(value = "p3") Person person) {
        Corporation corp = new Corporation();
        corp.setDepartments(new String[] { "行政部", "技术部", "人事部", "财务部" });
        String[] arr = new String[] { "经理", "副经理", "部门经理" };
        corp.setPositions(Arrays.asList(arr));
        Map<Integer, Person> employees = new HashMap<>();
        employees.put(1, firstPerson);
        employees.put(2, secondPerson);
        employees.put(3, person);
        corp.setEmployees(employees);
        return corp;
    }
    
    @Bean
    public ResourceBundleMessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("prop.message");
        return messageSource;
    }
    
    @Bean
    public CustomApplicationListener listener() {
        return new CustomApplicationListener();
    }
}
